package org.desktop.web.server;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.cheetah.encrypt.Encryptor;
import org.desktop.web.server.bean.Timer;
import org.desktop.web.server.bean.WorkingDay;
import org.desktop.web.shared.util.WebService;
import org.json.JSONArray;
import org.json.JSONObject;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gwt.dev.json.JsonObject;
import com.google.gwt.user.client.Cookies;

/**
 * Servlet implementation class BridgeSevlet
 */
public class BridgeSevlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	// key del cliente! (andra' messo dentro un parametro di inizializzazione o
	// dentro una property (magari all'avvio del server)
	private String clientKey = "ywPVZHW0CGB7IG833mzaeEPdDlaHDCZ0ujVksZQbBKIAsozYQ5JeBeuoLFexu11ZHCDmhYvv1z8H5LCdp8BvQfisjiF2pZ0HAYJ0";

	private Map<WebService, Method> services = new HashMap<WebService, Method>();

	@Override
	public void init() throws ServletException {
		// TODO Auto-generated method stub
		super.init();
		Class _this_ = this.getClass();
		try {
			services.put(
					WebService.NORMAL_WORKING_TIME,
					_this_.getDeclaredMethod("normalWorkingTime",
							HttpServletRequest.class, HttpServletResponse.class));
			services.put(WebService.AUTH, _this_.getDeclaredMethod("doAuth",
					HttpServletRequest.class, HttpServletResponse.class));
			services.put(
					WebService.GET_PROJECT_LIST_ADMIN,
					_this_.getDeclaredMethod("getProjectsAdmin",
							HttpServletRequest.class, HttpServletResponse.class));
			services.put(
					WebService.GET_USERS_BY_PROJECT,
					_this_.getDeclaredMethod("getUsers",
							HttpServletRequest.class, HttpServletResponse.class));

		} catch (NoSuchMethodException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public BridgeSevlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String name = request.getParameter("service");
		System.out.println("Service request: " + name);
		WebService[] ws = WebService.class.getEnumConstants();
		Method m = null;
		for (int i = 0; i < ws.length; i++) {
			WebService webService = ws[i];
			if (webService.name().equals(name)) {
				m = services.get(webService);
				break;
			}
		}
		if (m != null) {
			try {
				m.invoke(this, request, response);
			} catch (IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private void getUsers(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String token = request.getHeader("token");
		String url = "http://127.0.0.1:8080/timesheet/userses";
		URL _url = new URL(url);
		HttpURLConnection con = getUrlConnection(_url, "GET");
		con.setRequestProperty("Accept", "application/json");
		con.setRequestProperty("token", token);
		InputStream in = con.getInputStream();
		String result = IOUtils.toString(in);
		JSONArray users = new JSONArray(result);
		JSONArray usersResult = new JSONArray();
		for(int i=0;i<users.length();i++){
			JSONObject obj = users.getJSONObject(i);
			int id = obj.getInt("id");
			String descCustomer = obj.getJSONObject("idCustomer").getString("customerDesc");
			String descRole = obj.getJSONObject("idRole").getString("descRole");
			String login = obj.getString("login");
			JSONObject nobj = new JSONObject().put("id", id).put("descCustomer",descCustomer).put("descRole", descRole).put("login", login.toUpperCase());
			usersResult.put(nobj);
		}
		
		in.close();
		result = new StringBuilder("{\"records\":").append(usersResult.toString()).append("}")
				.toString();
		response.getOutputStream().write(result.getBytes());

	}

	private void getProjectsAdmin(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String token = request.getHeader("token");
		String url = "http://127.0.0.1:8080/timesheet/projectses";

		URL _url = new URL(url);
		HttpURLConnection con = getUrlConnection(_url, "GET");
		con.setRequestProperty("Accept", "application/json");
		con.setRequestProperty("token", token);
		System.out.println("token ricevuto: " + token);
		InputStream in = con.getInputStream();
		String result = IOUtils.toString(in);
		in.close();
		StringBuilder sb = new StringBuilder("{\"records\": ").append(result)
				.append("}");
		result = sb.toString();
		System.out.println(result);
		JSONObject obj = new JSONObject(result);
		System.out.println(obj.toString());
		response.getOutputStream().write(obj.toString().getBytes());

	}

	private void doAuth(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		System.out.println(IOUtils.toString(request.getInputStream()));
		String url = "http://127.0.0.1:8080/timesheet/auth/login";
		URL _url = new URL(url);
		String id = RandomStringUtils.randomAlphanumeric(30);
		HttpURLConnection con = getUrlConnection(_url, "POST");
		con.setRequestProperty("client-key", clientKey);
		con.setRequestProperty("session-id", id);
		InputStream in = con.getInputStream();
		String s = IOUtils.toString(in);
		in.close();
		if (s.equals(clientKey)) {
			// l'applicativo e' autorizzato a fare la login

			
			
			String username = request.getParameter("username");
			String password = request.getParameter("password");
			System.out.println(password);
			// ottenuto il client key mando username e password criptati
			String json = "{\"username\": \"" + username
					+ "\", \"password\": \"" + password + "\"}";
			Encryptor enc = new Encryptor(clientKey);
			byte[] encByte = enc.encryptString(json);
			_url = new URL(url + "enc");
			con = getUrlConnection(_url, "POST");
			con.setRequestProperty("session-id", id);
			con.setRequestProperty("Content-Type", "application/octet-stream");
			con.setRequestProperty("Accept", "application/json");
			OutputStream out = con.getOutputStream();
			out.write(encByte);
			in = con.getInputStream();
			s = IOUtils.toString(in);
			System.out.println("---> " + s);
			out.close();
			in.close();
			response.setContentType("text/html");
			response.setContentLength(s.getBytes().length);
			JSONObject obj = new JSONObject(s);
			System.out.println(obj.toString());
			response.getOutputStream().write(obj.toString().getBytes());

		}

	}

	public HttpURLConnection getUrlConnection(URL _url, String requestMethod)
			throws IOException, ProtocolException {
		HttpURLConnection con = (HttpURLConnection) _url.openConnection();
		con.setAllowUserInteraction(true);
		con.setDoInput(true);
		con.setDoOutput(true);
		con.setRequestMethod(requestMethod);
		return con;
	}

	private void normalWorkingTime(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		GregorianCalendar gcBLstart = getCalendar(9, 0);
		GregorianCalendar gcBLend = getCalendar(13, 0);
		GregorianCalendar gcALstart = getCalendar(14, 0);
		GregorianCalendar gcALend = getCalendar(18, 0);

		Timer bl = new Timer();
		bl.setStartTime(gcBLstart.getTime());
		bl.setEndTime(gcBLend.getTime());
		bl.setId(RandomStringUtils.randomAlphanumeric(30));
		Timer al = new Timer();
		al.setStartTime(gcALstart.getTime());
		al.setEndTime(gcALend.getTime());
		al.setId(RandomStringUtils.randomAlphanumeric(30));

		WorkingDay wd = new WorkingDay();

		wd.addRecord(bl);
		wd.addRecord(al);
		response.setContentType("application/json");
		ObjectMapper om = new ObjectMapper();
		om.writeValue(response.getOutputStream(), wd);
	}

	public static GregorianCalendar getCalendar(int hour, int minute) {
		GregorianCalendar gc = (GregorianCalendar) GregorianCalendar
				.getInstance();
		gc.set(Calendar.HOUR_OF_DAY, hour);
		gc.set(Calendar.MINUTE, minute);
		return gc;
	}

	private String getQuery(List<NameValuePair> params)
			throws UnsupportedEncodingException {
		StringBuilder result = new StringBuilder();
		boolean first = true;

		for (NameValuePair pair : params) {
			if (first)
				first = false;
			else
				result.append("&");

			result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
			result.append("=");
			result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
		}

		return result.toString();
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

	private void getCalendar(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		String url = "http://127.0.0.1:8080/timesheet/getcalendar";
		URLConnection con = new URL(url).openConnection();
		System.out.println("??????????????" + request.getParameter("id"));
		con.setAllowUserInteraction(true);
		con.setDoInput(true);
		con.setDoOutput(true);

		List<NameValuePair> params = new ArrayList<NameValuePair>();
		Enumeration<String> names = request.getParameterNames();

		while (names.hasMoreElements()) {
			String name = (String) names.nextElement();
			params.add(new BasicNameValuePair(name, request.getParameter(name)));
		}

		OutputStream os = con.getOutputStream();
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os,
				"UTF-8"));

		writer.write(getQuery(params));
		writer.flush();
		writer.close();
		os.close();

		InputStream in = con.getInputStream();
		response.setContentType("application/json");
		response.setContentLength(in.available());
		response.getOutputStream().write(IOUtils.toByteArray(in));
	}
}
